import { h } from 'vue'
import { message, notification } from 'ant-design-vue'
import { useStore } from '@/store'
import useClear from '@/hooks/useClear'
import { localStorage } from '@/utils'
import { AXIOS_TIMEOUT } from '@/utils/dictionaries'

/**
 * 请求方法
 */
export const METHOD = {
  GET: 'get',
  POST: 'post',
  DELETE: 'delete',
  PUT: 'put'
}

/**
 * 获取返回参数数据模型，自动识别分页数据、列表数据、详情数据
 *
 * @param {*} res
 */
const getResData = res => {
  const { data, totalNum, totalPage, currentPage, fullCount, scope } = res

  if (fullCount || scope) {
    return {
      list: data,
      total: totalNum,
      page: currentPage,
      pageSize: totalPage,
      fullCount,
      scope
    }
  }
  // 分页数据中任意有值都为分页数据
  if (currentPage && currentPage >= 1) {
    return {
      list: data,
      total: totalNum,
      page: currentPage,
      pageSize: totalPage
    }
  }
  return data ?? null
}

/**
 * 显示消息提示
 * 
 * @param {*} msg 
 * @param {*} options 
 * @returns 
 */
const showMessage = (msg, options = {}) => {
  if (!msg) return

  // 先解析config中_msgConfig配置信息
  const msgConfig = options?._msgConfig || {}

  message.error(Object.assign({}, msgConfig, {
    content: msg
  }))
}

/**
 * 登录失效的处理
 * 
 * @param {*} url 
 * @param {*} step 
 */
const clearToLogin = async (url, step) => {
  // const env = await new Promise(resolve => {
  //   uni?.getEnv(e => {
  //     resolve(e)
  //   })
  // })
  // if (env?.plus) {
  //   uni.webView.postMessage({
  //     data: {
  //       type: 'clearToLogin',
  //       msg: 'clearToLogin'
  //     }
  //   })
  //   return
  // }

  // pc端独立的处理
  message.destroy()

  // 拼接路由地址，清理所有/api/开始的下标
  let _path = url?.substr(url.indexOf('/api/')).replace(/\//g, '.')
  _path =
    _path.substr(_path.length - 1) === '.'
      ? _path.substr(0, _path.length - 1)
      : _path
  notification.error({
    message: '身份失效,请重新登录!',
    description: h('div', { class: 'custom-description' }, `[${step}]${_path}`),
    placement: 'top'
  })
  const { build } = useClear()
  build()
  useNuxtApp().$toRoutePath('/')
}

/**
 * 响应信息处理
 */
const handleResponse = (response, options) => {
  const { url, _data, status } = response

  const { spin } = useStore()
  spin.close()

  // 检查当前http状态
  if (status != 200) {
    // 说明为异常状态，根据状态码进行消息提示
    if (status == 401 || status == 403) {
      const erMsg = '请求未授权'
       showMessage(erMsg, options)
       return Promise.reject(erMsg)
    }
    if (status == 405) {
      const erMsg = '不允许跨域处理'
      showMessage(erMsg, options)
      return Promise.reject(erMsg)
    }
    if (status == 500 || status == 502 || status == 503 || status == 504) {
      const erMsg = '服务器异常，请稍后重试'
      showMessage(erMsg, options)
      return Promise.reject(erMsg)
    }
    const erMsg = '请求无效'
    showMessage(erMsg, options)
    return Promise.reject(erMsg)
  }

  /**
   * 成功消息
   */
  if (_data.code === '200') {
    return Promise.resolve(getResData(_data))
  }

  // 权限不足提示
  if (_data.code === 'A300500') {
    clearToLogin(url, 1)
    return Promise.reject(_data)
  }

  // 数据权限不足提示
  if (_data.code === '200110' || _data.code === '200111') {
    return Promise.reject(_data)
  }

  // 强制跳转登录授权
  if (!options.hideLogin && _data.code === '401') {
    clearToLogin(url, 2)
    return Promise.reject(_data)
  }

  // 异地登录提醒
  if (_data.code === 'A201502') {
    return Promise.reject(_data)
  }

  // 清空所有提示，重新提示异常清空
  message.destroy()

  if (_data.code === 'UT0000') {
    showMessage('数据加载遇到问题，请稍后再试', options)
  } else {
    showMessage(_data.msg || _data.message || DEFAULT_MESSAGE, options)
  }
  return Promise.reject(_data)
}

/**
 * get方法传递数组形式参数
 * 
 * @param {*} params 
 * @returns 
 */
const paramsSerializer = (params) => {
  if (!params) return
  const query = params
  Object.entries(query).forEach(([key, val]) => {
    if (typeof val === 'object' && Array.isArray(val) && val !== null) {
      query[`${key}[]`] = toRaw(val).map((v) => JSON.stringify(v))
      delete query[key]
    }
  })
  return query
}

/**
 * 单独创建请求服务
 */
const fetch = $fetch.create({
  // 请求拦截器
  onRequest({ options }) {
    // get方法传递数组形式参数
    options.params = paramsSerializer(options.params)
    // 添加baseURL,nuxt3环境变量要从useRuntimeConfig里面取
    const { public: { apiBase } } = useRuntimeConfig()
    options.baseURL = apiBase

    // 转化header信息
    options.headers = new Headers(options.headers)
    options.headers.set('Nb-Device-Id', localStorage.get('deviceId', ''))

    // 添加请求头,没登录不携带token
    const { user } = useStore()
    if (!options.headers.get('Authorization') && user.getToken) {
      options.headers.set('Authorization', user.getToken)
    }
  },
  // 响应拦截
  onResponse({ response, options }) {
    return handleResponse(response, options)
  },
  // 错误处理
  onResponseError({ response }) {
    const { spin } = useStore()
    spin.close()
    return Promise.reject(response._data)
  }
})

// 自动导出
export const useHttp = {
  get: (url, data, { timeout = AXIOS_TIMEOUT, headers = {}, ...options } = {}) => {
    return fetch(url, {
      method: METHOD.GET,
      params: data ? data : '',
      timeout: timeout ? timeout : AXIOS_TIMEOUT,
      headers: headers,
      ...options
    })
  },
  post: (url, data, { timeout = AXIOS_TIMEOUT, headers = {}, ...options } = {}) => {
    return fetch(url, {
      method: METHOD.POST,
      body: data ? data : '',
      timeout: timeout ? timeout : AXIOS_TIMEOUT,
      headers: headers,
      ...options
    })
  },
  put: (url, data, { timeout = AXIOS_TIMEOUT, headers = {}, ...options } = {}) => {
    return fetch(url, {
      method: METHOD.PUT,
      body: data ? data : '',
      timeout: timeout ? timeout : AXIOS_TIMEOUT,
      headers: headers,
      ...options
    })
  },
  delete: (url, data, { timeout = AXIOS_TIMEOUT, headers = {}, ...options } = {}) => {
    return fetch(url, {
      method: METHOD.DELETE,
      body: data ? data : '',
      timeout: timeout ? timeout : AXIOS_TIMEOUT,
      headers: headers,
      ...options
    })
  }
}
